package edu.tfh.s2.ehkbot.gerete.sensoren.simulation;

import edu.tfh.s2.ehkbot.daten.Protokoll;
import edu.tfh.s2.ehkbot.gerete.Fahrgestell;
import edu.tfh.s2.ehkbot.gerete.sensoren.IndoorGPS.IndoorGPSState;
import edu.tfh.s2.ehkbot.steuerung.Position;
import edu.tfh.s2.ehkbot.steuerung.Richtung;
import edu.tfh.s2.ehkbot.util.Observer;
import edu.tfh.s2.ehkbot.util.Subject;

/**
 * Implementiert das State für den Zustand Simulation von IndoorGPS. IndoorGPSSimulation nutzt das Observer
 * Pattern (ist Beobchter von Fahrgestell).
 * 
 * <pre>
 *  - IndoorGPSSimulation methoden aufrufe sind Thread-Sicher da 
 *    z.b. Simulierte Abstandssensoren ihren Messwert
 *    in einen anderen Thread aktualiesieren.
 * </pre>
 */
public class IndoorGPSSimulation implements IndoorGPSState, Observer, Cloneable {
	private Position currentPosition;
	private Richtung richtung;
	private Subject sub;

	/**
	 * Konstruktor der das IndoorGPS initaliesiert mit Start Position und Richtung.
	 * 
	 * @param startPosition
	 *            Die Start Position.
	 * @param startRichtung
	 *            Die Start richtung.
	 */
	public IndoorGPSSimulation(Position startPosition, Richtung startRichtung) {
		this.richtung = startRichtung;
		this.currentPosition = startPosition;
	}

	/**
	 * @see java.lang.Object#clone()
	 */
	@Override
	public Object clone() {
		try {
			return super.clone();
		} catch (CloneNotSupportedException e) {
			Protokoll.getInstanc().exception(e);
		}
		return null;
	}

	/**
	 * @see edu.tfh.s2.ehkbot.gerete.sensoren.IndoorGPS.IndoorGPSState#getCurrentPosition()
	 */
	@Override
	public Position getCurrentPosition() {
		synchronized (this) {
			return (Position) currentPosition.clone();
		}
	}

	/**
	 * @see edu.tfh.s2.ehkbot.gerete.sensoren.IndoorGPS.IndoorGPSState#getRichtung()
	 */
	@Override
	public Richtung getRichtung() {
		synchronized (this) {
			return richtung;
		}
	}

	/**
	 * Registriert das Subjekt und attached this zu den Subjekt.
	 * 
	 * @param sub
	 *            Das zu Beobachtende Subjekt.
	 */
	public void registerSubject(Subject sub) {
		synchronized (this) {
			this.sub = sub;
			sub.attach(this);
		}
	}

	/**
	 * @see edu.tfh.s2.ehkbot.util.Observer#update()
	 */
	@Override
	public void update() {
		synchronized (this) {
			Object status = sub.getState();
			if (!(status instanceof Fahrgestell))
				return;
			Fahrgestell fahrgestell = (Fahrgestell) status;
			Fahrgestell.FahrBefehl b = fahrgestell.getBefehlsLogbuch().lastElement();
			if (b.istDrehBefehl()) {
				richtung = richtung.add(b.getDreheBefehl());
			} else if (b.istFahrBefehl()) {
				long mm = b.getFahreBefehl();
				Position p = getCurrentPosition();
				int x = (int) (p.getX() + Math.round(mm * Math.cos(richtung.getAlsRad())));
				int y = (int) (p.getY() - Math.round(mm * Math.sin(richtung.getAlsRad())));
				int z = p.getZ();
				currentPosition = new Position(x, y, z);
			}
		}
	}
}